//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package http_custom_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas/api-server/api_common"
	"atomgit.com/openlinksaas/api-server/dao"
	"atomgit.com/openlinksaas/api-server/dao/api_coll_dao"
	"atomgit.com/openlinksaas/api-server/dao/project_entry_dao"
	"atomgit.com/openlinksaas/api-server/utils"
	"atomgit.com/openlinksaas/proto-gen-go.git/http_custom_api"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_entry_api"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

func (apiImpl *HttpCustomApiImpl) CreateApiItem(ctx context.Context, req *http_custom_api.CreateApiItemRequest) (*http_custom_api.CreateApiItemResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &http_custom_api.CreateApiItemResponse{
			Code:   http_custom_api.CreateApiItemResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &http_custom_api.CreateApiItemResponse{
			Code:   http_custom_api.CreateApiItemResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &http_custom_api.CreateApiItemResponse{
			Code:   http_custom_api.CreateApiItemResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &http_custom_api.CreateApiItemResponse{
			Code:   http_custom_api.CreateApiItemResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	//检查信息是否存在
	entryItem, err := project_entry_dao.EntryDao.Get(ctx, req.ApiCollId, req.ProjectId)
	if err != nil {
		return &http_custom_api.CreateApiItemResponse{
			Code:   http_custom_api.CreateApiItemResponse_CODE_NO_CUSTOM_API,
			ErrMsg: "自定义接口不存在",
		}, nil
	}
	if entryItem.EntryType != uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_API_COLL) {
		return &http_custom_api.CreateApiItemResponse{
			Code:   http_custom_api.CreateApiItemResponse_CODE_NO_CUSTOM_API,
			ErrMsg: "自定义接口不存在",
		}, nil
	}

	hasUpdatePerm := api_common.CheckEntryCanUpdate(sessionItem, projectItem, roleItem, entryItem)

	if !hasUpdatePerm {
		return &http_custom_api.CreateApiItemResponse{
			Code:   http_custom_api.CreateApiItemResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	exist, err := api_coll_dao.ApiGroupDao.Exist(ctx, req.ApiCollId, req.GroupId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &http_custom_api.CreateApiItemResponse{
			Code:   http_custom_api.CreateApiItemResponse_CODE_NO_GROUP,
			ErrMsg: "接口集分组不存在",
		}, nil
	}

	apiItemId := uuid.NewString()
	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		paramList := []api_coll_dao.HttpKeyValueDbItem{}
		for _, p := range req.ParamList {
			paramList = append(paramList, api_coll_dao.HttpKeyValueDbItem{
				Id:    p.Id,
				Key:   p.Key,
				Value: p.Value,
			})
		}
		headerList := []api_coll_dao.HttpKeyValueDbItem{}
		for _, p := range req.HeaderList {
			headerList = append(headerList, api_coll_dao.HttpKeyValueDbItem{
				Id:    p.Id,
				Key:   p.Key,
				Value: p.Value,
			})
		}

		dbItem := &api_coll_dao.ApiItemInfoDbItem{
			ApiItemId:   apiItemId,
			ApiItemName: req.ApiItemName,
			ApiCollId:   req.ApiCollId,
			GroupId:     req.GroupId,
			Method:      req.Method,
			Url:         req.Url,
			ParamList:   paramList,
			HeaderList:  headerList,
			BodyType:    uint32(req.BodyType),
			ContentType: req.ContentType,
			TimeStamp:   nowTime,
		}
		if req.BodyType == http_custom_api.HTTP_BODY_TYPE_HTTP_BODY_TEXT {
			body := req.Body.(*http_custom_api.CreateApiItemRequest_TextBody)
			dbItem.TextBody = &body.TextBody
		} else if req.BodyType == http_custom_api.HTTP_BODY_TYPE_HTTP_BODY_URL_ENCODE {
			body := req.Body.(*http_custom_api.CreateApiItemRequest_UrlEncodeBody)
			tmpList := []api_coll_dao.HttpKeyValueDbItem{}
			for _, p := range body.UrlEncodeBody.ParamList {
				tmpList = append(tmpList, api_coll_dao.HttpKeyValueDbItem{
					Id:    p.Id,
					Key:   p.Key,
					Value: p.Value,
				})
			}
			dbItem.UrlEncodeBody = &api_coll_dao.UrlEncodeBodyDbItem{
				ParamList: tmpList,
			}
		} else if req.BodyType == http_custom_api.HTTP_BODY_TYPE_HTTP_BODY_MULTI_PART {
			body := req.Body.(*http_custom_api.CreateApiItemRequest_MultiPartBody)
			tmpList := []api_coll_dao.MultiPartDbItem{}
			for _, p := range body.MultiPartBody.PartList {
				tmpList = append(tmpList, api_coll_dao.MultiPartDbItem{
					Id:     p.Id,
					Key:    p.Key,
					Value:  p.Value,
					IsFile: p.IsFile,
				})
			}
			dbItem.MultiPartBody = &api_coll_dao.MultiPartBodyDbItem{
				PartList: tmpList,
			}
		}
		err = api_coll_dao.ApiItemDao.Insert(sessCtx, dbItem)
		if err != nil {
			return nil, err
		}
		count, err := api_coll_dao.ApiItemDao.CountByGroup(sessCtx, req.ApiCollId, req.GroupId)
		if err != nil {
			return nil, err
		}
		err = api_coll_dao.ApiGroupDao.UpdateItemCount(sessCtx, req.ApiCollId, req.GroupId, count)
		if err != nil {
			return nil, err
		}
		return &http_custom_api.CreateApiItemResponse{
			Code:      http_custom_api.CreateApiItemResponse_CODE_OK,
			ApiItemId: apiItemId,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*http_custom_api.CreateApiItemResponse), nil
}

func (apiImpl *HttpCustomApiImpl) UpdateApiItem(ctx context.Context, req *http_custom_api.UpdateApiItemRequest) (*http_custom_api.UpdateApiItemResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &http_custom_api.UpdateApiItemResponse{
			Code:   http_custom_api.UpdateApiItemResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &http_custom_api.UpdateApiItemResponse{
			Code:   http_custom_api.UpdateApiItemResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &http_custom_api.UpdateApiItemResponse{
			Code:   http_custom_api.UpdateApiItemResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &http_custom_api.UpdateApiItemResponse{
			Code:   http_custom_api.UpdateApiItemResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	//检查信息是否存在
	entryItem, err := project_entry_dao.EntryDao.Get(ctx, req.ApiCollId, req.ProjectId)
	if err != nil {
		return &http_custom_api.UpdateApiItemResponse{
			Code:   http_custom_api.UpdateApiItemResponse_CODE_NO_CUSTOM_API,
			ErrMsg: "自定义接口不存在",
		}, nil
	}
	if entryItem.EntryType != uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_API_COLL) {
		return &http_custom_api.UpdateApiItemResponse{
			Code:   http_custom_api.UpdateApiItemResponse_CODE_NO_CUSTOM_API,
			ErrMsg: "自定义接口不存在",
		}, nil
	}

	hasUpdatePerm := api_common.CheckEntryCanUpdate(sessionItem, projectItem, roleItem, entryItem)

	if !hasUpdatePerm {
		return &http_custom_api.UpdateApiItemResponse{
			Code:   http_custom_api.UpdateApiItemResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	exist, err := api_coll_dao.ApiGroupDao.Exist(ctx, req.ApiCollId, req.GroupId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &http_custom_api.UpdateApiItemResponse{
			Code:   http_custom_api.UpdateApiItemResponse_CODE_NO_GROUP,
			ErrMsg: "接口集分组不存在",
		}, nil
	}
	apiItemItem, err := api_coll_dao.ApiItemDao.Get(ctx, req.ApiCollId, req.ApiItemId)
	if err != nil {
		return &http_custom_api.UpdateApiItemResponse{
			Code:   http_custom_api.UpdateApiItemResponse_CODE_NO_API_ITEM,
			ErrMsg: "接口集接口不存在",
		}, nil
	}

	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		paramList := []api_coll_dao.HttpKeyValueDbItem{}
		for _, p := range req.ParamList {
			paramList = append(paramList, api_coll_dao.HttpKeyValueDbItem{
				Id:    p.Id,
				Key:   p.Key,
				Value: p.Value,
			})
		}
		headerList := []api_coll_dao.HttpKeyValueDbItem{}
		for _, p := range req.HeaderList {
			headerList = append(headerList, api_coll_dao.HttpKeyValueDbItem{
				Id:    p.Id,
				Key:   p.Key,
				Value: p.Value,
			})
		}

		dbItem := &api_coll_dao.ApiItemInfoDbItem{
			ApiItemId:   req.ApiItemId,
			ApiItemName: req.ApiItemName,
			ApiCollId:   req.ApiCollId,
			GroupId:     req.GroupId,
			Method:      req.Method,
			Url:         req.Url,
			ParamList:   paramList,
			HeaderList:  headerList,
			BodyType:    uint32(req.BodyType),
			ContentType: req.ContentType,
			TimeStamp:   nowTime,
		}
		if req.BodyType == http_custom_api.HTTP_BODY_TYPE_HTTP_BODY_TEXT {
			body := req.Body.(*http_custom_api.UpdateApiItemRequest_TextBody)
			dbItem.TextBody = &body.TextBody
		} else if req.BodyType == http_custom_api.HTTP_BODY_TYPE_HTTP_BODY_URL_ENCODE {
			body := req.Body.(*http_custom_api.UpdateApiItemRequest_UrlEncodeBody)
			tmpList := []api_coll_dao.HttpKeyValueDbItem{}
			for _, p := range body.UrlEncodeBody.ParamList {
				tmpList = append(tmpList, api_coll_dao.HttpKeyValueDbItem{
					Id:    p.Id,
					Key:   p.Key,
					Value: p.Value,
				})
			}
			dbItem.UrlEncodeBody = &api_coll_dao.UrlEncodeBodyDbItem{
				ParamList: tmpList,
			}
		} else if req.BodyType == http_custom_api.HTTP_BODY_TYPE_HTTP_BODY_MULTI_PART {
			body := req.Body.(*http_custom_api.UpdateApiItemRequest_MultiPartBody)
			tmpList := []api_coll_dao.MultiPartDbItem{}
			for _, p := range body.MultiPartBody.PartList {
				tmpList = append(tmpList, api_coll_dao.MultiPartDbItem{
					Id:     p.Id,
					Key:    p.Key,
					Value:  p.Value,
					IsFile: p.IsFile,
				})
			}
			dbItem.MultiPartBody = &api_coll_dao.MultiPartBodyDbItem{
				PartList: tmpList,
			}
		}
		err = api_coll_dao.ApiItemDao.Update(sessCtx, dbItem)
		if err != nil {
			return nil, err
		}
		if req.GroupId != apiItemItem.GroupId {
			count, err := api_coll_dao.ApiItemDao.CountByGroup(sessCtx, req.ApiCollId, req.GroupId)
			if err != nil {
				return nil, err
			}
			err = api_coll_dao.ApiGroupDao.UpdateItemCount(sessCtx, req.ApiCollId, req.GroupId, count)
			if err != nil {
				return nil, err
			}

			count, err = api_coll_dao.ApiItemDao.CountByGroup(sessCtx, req.ApiCollId, apiItemItem.GroupId)
			if err != nil {
				return nil, err
			}
			err = api_coll_dao.ApiGroupDao.UpdateItemCount(sessCtx, req.ApiCollId, apiItemItem.GroupId, count)
			if err != nil {
				return nil, err
			}
		}
		return &http_custom_api.UpdateApiItemResponse{
			Code: http_custom_api.UpdateApiItemResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*http_custom_api.UpdateApiItemResponse), nil
}

func (apiImpl *HttpCustomApiImpl) ListApiItem(ctx context.Context, req *http_custom_api.ListApiItemRequest) (*http_custom_api.ListApiItemResponse, error) {
	emptyList := []*http_custom_api.ApiItemInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &http_custom_api.ListApiItemResponse{
			Code:     http_custom_api.ListApiItemResponse_CODE_WRONG_SESSION,
			ErrMsg:   "会话不存在",
			ItemList: emptyList,
		}, nil
	}
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &http_custom_api.ListApiItemResponse{
			Code:     http_custom_api.ListApiItemResponse_CODE_NO_PROJECT,
			ErrMsg:   "项目不存在",
			ItemList: emptyList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &http_custom_api.ListApiItemResponse{
			Code:     http_custom_api.ListApiItemResponse_CODE_NO_PERMISSION,
			ErrMsg:   "没有权限",
			ItemList: emptyList,
		}, nil
	} else if err != nil {
		return nil, err
	}

	exist, err := api_coll_dao.CustomExtraDao.Exist(ctx, req.ApiCollId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &http_custom_api.ListApiItemResponse{
			Code:     http_custom_api.ListApiItemResponse_CODE_NO_CUSTOM_API,
			ErrMsg:   "自定义接口集不存在",
			ItemList: emptyList,
		}, nil
	}
	if req.FilterByGroupId {
		exist, err = api_coll_dao.ApiGroupDao.Exist(ctx, req.ApiCollId, req.GroupId)
		if err != nil {
			return nil, err
		}
		if !exist {
			return &http_custom_api.ListApiItemResponse{
				Code:     http_custom_api.ListApiItemResponse_CODE_NO_GROUP,
				ErrMsg:   "接口集接口不存在",
				ItemList: emptyList,
			}, nil
		}
	}

	apiItemItemList, err := api_coll_dao.ApiItemDao.List(ctx, req.ApiCollId, req.FilterByGroupId, req.GroupId)
	if err != nil {
		return nil, err
	}
	itemList := []*http_custom_api.ApiItemInfo{}
	for _, apiItemItem := range apiItemItemList {
		itemList = append(itemList, apiItemItem.ToApiItemInfo())
	}
	return &http_custom_api.ListApiItemResponse{
		Code:     http_custom_api.ListApiItemResponse_CODE_OK,
		ItemList: itemList,
	}, nil
}

func (apiImpl *HttpCustomApiImpl) GetApiItem(ctx context.Context, req *http_custom_api.GetApiItemRequest) (*http_custom_api.GetApiItemResponse, error) {
	emptyItem := &http_custom_api.ApiItemInfo{
		ParamList:  []*http_custom_api.HttpKeyValue{},
		HeaderList: []*http_custom_api.HttpKeyValue{},
		Body:       &http_custom_api.ApiItemInfo_NodyBody{},
	}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &http_custom_api.GetApiItemResponse{
			Code:     http_custom_api.GetApiItemResponse_CODE_WRONG_SESSION,
			ErrMsg:   "会话不存在",
			ItemInfo: emptyItem,
		}, nil
	}
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &http_custom_api.GetApiItemResponse{
			Code:     http_custom_api.GetApiItemResponse_CODE_NO_PROJECT,
			ErrMsg:   "项目不存在",
			ItemInfo: emptyItem,
		}, nil
	} else if err == utils.ErrNoRole {
		return &http_custom_api.GetApiItemResponse{
			Code:     http_custom_api.GetApiItemResponse_CODE_NO_PERMISSION,
			ErrMsg:   "没有权限",
			ItemInfo: emptyItem,
		}, nil
	} else if err != nil {
		return nil, err
	}

	exist, err := api_coll_dao.CustomExtraDao.Exist(ctx, req.ApiCollId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &http_custom_api.GetApiItemResponse{
			Code:     http_custom_api.GetApiItemResponse_CODE_NO_CUSTOM_API,
			ErrMsg:   "自定义接口集不存在",
			ItemInfo: emptyItem,
		}, nil
	}
	apiItemItem, err := api_coll_dao.ApiItemDao.Get(ctx, req.ApiCollId, req.ApiItemId)
	if err != nil {
		return &http_custom_api.GetApiItemResponse{
			Code:     http_custom_api.GetApiItemResponse_CODE_NO_API_ITEM,
			ErrMsg:   "接口不存在",
			ItemInfo: emptyItem,
		}, nil
	}
	return &http_custom_api.GetApiItemResponse{
		Code:     http_custom_api.GetApiItemResponse_CODE_OK,
		ItemInfo: apiItemItem.ToApiItemInfo(),
	}, nil
}

func (apiImpl *HttpCustomApiImpl) RemoveApiItem(ctx context.Context, req *http_custom_api.RemoveApiItemRequest) (*http_custom_api.RemoveApiItemResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &http_custom_api.RemoveApiItemResponse{
			Code:   http_custom_api.RemoveApiItemResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &http_custom_api.RemoveApiItemResponse{
			Code:   http_custom_api.RemoveApiItemResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &http_custom_api.RemoveApiItemResponse{
			Code:   http_custom_api.RemoveApiItemResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &http_custom_api.RemoveApiItemResponse{
			Code:   http_custom_api.RemoveApiItemResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	//检查信息是否存在
	entryItem, err := project_entry_dao.EntryDao.Get(ctx, req.ApiCollId, req.ProjectId)
	if err != nil {
		return &http_custom_api.RemoveApiItemResponse{
			Code:   http_custom_api.RemoveApiItemResponse_CODE_NO_CUSTOM_API,
			ErrMsg: "自定义接口不存在",
		}, nil
	}
	if entryItem.EntryType != uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_API_COLL) {
		return &http_custom_api.RemoveApiItemResponse{
			Code:   http_custom_api.RemoveApiItemResponse_CODE_NO_CUSTOM_API,
			ErrMsg: "自定义接口不存在",
		}, nil
	}

	hasUpdatePerm := api_common.CheckEntryCanUpdate(sessionItem, projectItem, roleItem, entryItem)

	if !hasUpdatePerm {
		return &http_custom_api.RemoveApiItemResponse{
			Code:   http_custom_api.RemoveApiItemResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	apiItemItem, err := api_coll_dao.ApiItemDao.Get(ctx, req.ApiCollId, req.ApiItemId)
	if err != nil {
		return &http_custom_api.RemoveApiItemResponse{
			Code:   http_custom_api.RemoveApiItemResponse_CODE_NO_API_ITEM,
			ErrMsg: "接口集接口不存在",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = api_coll_dao.ApiItemDao.Remove(sessCtx, req.ApiCollId, req.ApiItemId)
		if err != nil {
			return nil, err
		}
		count, err := api_coll_dao.ApiItemDao.CountByGroup(sessCtx, req.ApiCollId, apiItemItem.GroupId)
		if err != nil {
			return nil, err
		}
		err = api_coll_dao.ApiGroupDao.UpdateItemCount(sessCtx, req.ApiCollId, apiItemItem.GroupId, count)
		if err != nil {
			return nil, err
		}
		return &http_custom_api.RemoveApiItemResponse{
			Code: http_custom_api.RemoveApiItemResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*http_custom_api.RemoveApiItemResponse), nil
}
